<script setup lang="ts">
import { h, ref, reactive, onMounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { NSpace, NDataTable, NButton, NCheckbox, useNotification, useDialog } from 'naive-ui'
import type { DataTableColumns } from 'naive-ui'
import http from '@/tools/http'
import { toTree } from '@/tools/tree'
import { useUserStore } from '@/stores/userStore'
import DataAuthConfig from './data-auth-config.vue'

const notification = useNotification()
const dialog = useDialog()
const route = useRoute()
const router = useRouter()
const userStore = useUserStore()

type RowData = {
    label: string
    value: string
    key: number | string
    icon?: Object
    data: any
    children?: RowData[],
    authList?: RowData[]
}

type MenuData = {
    menuCode: string
    menuName?: string
    menuStatus?: string
    menuType?: string
    loadType?: string
    menuUrl?: string
    menuIcon?: string
    menuSort?: number
    menuParent?: string
    remark?: string
}

const formData = reactive<any>({
    objId: "",
    objType: "",
    permIdList: []
})

let menuList: MenuData[] = []
const menuTreeData = ref<RowData[]>([])
const title = ref<string>("功能")

const columns: DataTableColumns<RowData> = [
    {
        type: 'selection'
    },
    {
        title: '菜单名称',
        key: 'label',
        width: 240
    },
    {
        title: '菜单功能',
        key: 'value',
        render(rowData: RowData, rowIndex: number) {
            const authCheckboxList: any[] = []
            authCheckboxList.push(h(
                NCheckbox,
                {
                    size: 'small',
                    checked: permIdList.includes(rowData.value) ? rowData.value : '',
                    checkedValue: rowData.value,
                    uncheckedValue: 'remove:' + rowData.value,
                    onUpdateChecked: (checked: boolean) => {
                        const checkedStr: string = String(checked)
                        if (checkedStr.includes("remove")) {
                            const permId = checkedStr.substring(7)
                            const index = selectedRowKeys.findIndex(item => item === permId)
                            if (index !== -1) {
                                selectedRowKeys.splice(index, 1)
                            }
                            const menuParent = rowData.data.menuParent
                            if (menuParent && menuParent !== "") {
                                const index = selectedRowKeys.findIndex(item => item === menuParent)
                                if (index !== -1) {
                                    selectedRowKeys.splice(index, 1)
                                }
                            }
                            const permIndex = permIdList.findIndex(item => item === permId)
                            if (permIndex !== -1) {
                                permIdList.splice(permIndex, 1)
                            }
                            if (rowData.authList) {
                                for (let i = 0; i < rowData.authList.length; i++) {
                                    for (let j = 0; j < permIdList.length; j++) {
                                        if (permIdList[j] === rowData.authList[i].value) {
                                            permIdList.splice(j, 1)
                                            break
                                        }
                                    }
                                }
                            }
                        } else {
                            const menuParent = rowData.data.menuParent
                            if (menuParent && menuParent !== "") {
                                if (!permIdList.includes(menuParent)) {
                                    permIdList.push(menuParent)
                                }
                            }
                            selectedRowKeys.push(checkedStr)
                            permIdList.push(checkedStr)
                        }
                    }
                },
                () => "查询"
            ))
            if (rowData.authList) {
                for (let i = 0; i < rowData.authList.length; i++) {
                    authCheckboxList.push(h(
                        NCheckbox,
                        {
                            size: 'small',
                            checked: permIdList.includes(rowData.authList[i].value) ? rowData.authList[i].value : '',
                            checkedValue: rowData.authList[i].value,
                            uncheckedValue: 'remove:' + rowData.authList[i].value,
                            disabled: !permIdList.includes(rowData.authList[i].data.menuParent),
                            onUpdateChecked: (checked: boolean) => {
                                const checkedStr: string = String(checked)
                                if (checkedStr.includes("remove")) {
                                    const permId = checkedStr.substring(7)
                                    const index = permIdList.findIndex(item => item === permId)
                                    if (index !== -1) {
                                        permIdList.splice(index, 1)
                                    }
                                } else {
                                    permIdList.push(checkedStr)
                                }
                            }
                        },
                        () => rowData.authList ? rowData.authList[i].label : ''
                    ))
                }
            }
            return h(
                NSpace, null, () => authCheckboxList
            )
        }
    }
]

const selectedRowKeys = reactive<string[]>([])
const permIdList = reactive<string[]>([])

onMounted(() => {
    formData.objType = route.query.objType
    formData.objId = route.query.objId
    listMenu()
})

function onUpdateCheckedRowKeys(keys: Array<string | number>, rows: object[], meta: { row: object | undefined, action: 'check' | 'uncheck' | 'checkAll' | 'uncheckAll' }) {
    if (meta.action === 'checkAll') {
        permIdList.length = 0
        for (let i = 0; i < rows.length; i++) {
            const temp = (rows[i] as RowData)
            if (temp.data.menuType === '1' && temp.authList) {
                for (let j = 0; j < temp.authList.length; j++) {
                    permIdList.push(temp.authList[j].value)
                }
            }
            const menuParent = temp.data.menuParent
            if (menuParent && menuParent !== "") {
                if (!permIdList.includes(menuParent)) {
                    permIdList.push(menuParent)
                }
            }
            permIdList.push((rows[i] as RowData).value)
        }
    }
    if (meta.action === 'check') {
        for (let i = 0; i < rows.length; i++) {
            const temp = (rows[i] as RowData)
            if (permIdList.includes(temp.value)) {
                continue
            }
            if (temp.data.menuType === '1' && temp.authList) {
                for (let j = 0; j < temp.authList.length; j++) {
                    permIdList.push(temp.authList[j].value)
                }
            }
            const menuParent = temp.data.menuParent
            if (menuParent && menuParent !== "") {
                if (!permIdList.includes(menuParent)) {
                    permIdList.push(menuParent)
                }
            }
            permIdList.push((rows[i] as RowData).value)
        }
    }
    if (meta.action === 'uncheckAll') {
        permIdList.length = 0
    }
    if (meta.action === 'uncheck') {
        const temp = (meta.row as RowData)
        uncheck(temp)
    }
    selectedRowKeys.length = 0
    for (let i = 0; i < keys.length; i++) {
        selectedRowKeys.push(keys[i] as string)
    }
}

function uncheck(row: RowData) {
    if (row.data.menuType === '0') {
        const index = permIdList.findIndex(item => item === row.value)
        if (index !== -1) {
            permIdList.splice(index, 1)
        }
        if (row.children) {
            for (let i = 0; i < row.children.length; i++) {
                uncheck(row.children[i])
            }
        }
    }
    if (row.data.menuType === '1') {
        const index = permIdList.findIndex(item => item === row.value)
        if (index !== -1) {
            permIdList.splice(index, 1)
        }
        if (row.authList) {
            for (let i = 0; i < row.authList.length; i++) {
                const temp = row.authList[i]
                const index = permIdList.findIndex(item => item === temp.value)
                if (index !== -1) {
                    permIdList.splice(index, 1)
                }
            }
        }
    }
}

function listMenu() {
    const whiteList: string[] = [
        "login",
        "user-info",
        "user-message",
        "revise-pwd",
        "home",
        "no-auth"
    ]
    http.post("/menu/list").then(({ data }) => {
        if (data.code === "0") {
            menuList = data.data
            menuList = menuList.filter(menu => !whiteList.includes(menu.menuCode))
            menuTreeData.value = toTree(menuList, "menuParent", null, "menuCode", "menuName", "menuCode")
            menuTreeData.value = formateAuth(menuTreeData.value)
            getAuthList()
        }
    })
}

function formateAuth(treeData: RowData[] | undefined): RowData[] {
    const newData: RowData[] = []
    if (treeData) {
        for (let i = 0; i < treeData.length; i++) {
            if (treeData[i].data.menuType === '0') {
                const newChild = formateAuth(treeData[i].children)
                newData.push({
                    label: treeData[i].label,
                    value: treeData[i].value,
                    key: treeData[i].key,
                    data: treeData[i].data,
                    children: newChild
                })
            }
            if (treeData[i].data.menuType === '1') {
                newData.push({
                    label: treeData[i].label,
                    value: treeData[i].value,
                    key: treeData[i].key,
                    data: treeData[i].data,
                    authList: treeData[i].children
                })
            }
        }
    }
    return newData
}

function getAuthList() {
    const request = {
        pageNum: 0,
        pageSize: 0,
        objId: formData.objId,
        objType: formData.objType
    }
    http.post("/obj/auth/page", request).then(({ data }) => {
        if (data.code === "0") {
            selectedRowKeys.length = 0
            permIdList.length = 0
            for (let i = 0; i < data.data.list.length; i++) {
                for (let j = 0; j < menuList.length; j++) {
                    if (menuList[j].menuCode === data.data.list[i].permId && menuList[j].menuType === '1') {
                        selectedRowKeys.push(menuList[j].menuCode)
                        break
                    }
                }
                permIdList.push(data.data.list[i].permId)
            }
        }
    })
}

function submit() {
    dialog.create({
        title: '温馨提示',
        content: '确定修改权限吗？',
        positiveText: '确定',
        negativeText: '取消',
        onPositiveClick: () => {
            formData.permIdList = permIdList
            http.post("/obj/auth/maintain", formData).then(({ data }) => {
                if (data.code === '0') {
                    notification['success']({
                        content: '权限维护更新成功',
                        meta: `${data.msg}`,
                        duration: 2500,
                        keepAliveOnHover: true
                    })
                    getAuthList()
                }
            })
        }
    })
}

type DataAuth = {
    objId?: string
    objType?: string
    dataType?: string
    dataObjCode?: string
    dataScope?: string
}

const userDataAuth = ref<string>("0")
const orgDataAuthList = reactive<DataAuth[]>([])

function listDataAuth() {
    const request = {
        pageNum: 0,
        pageSize: 0,
        objId: formData.objId,
        objType: formData.objType
    }
    http.post("/data/auth/page", request).then(({ data }) => {
        if (data.code === "0") {
            orgDataAuthList.length = 0
            for (let i = 0; i < data.data.list.length; i++) {
                // 用户
                if (data.data.list[i].dataType === "0") {
                    userDataAuth.value = data.data.list[i].dataScope
                }
                // 机构
                if (data.data.list[i].dataType === "1") {
                    orgDataAuthList.push(data.data.list[i])
                }
            }
        }
    })
}
</script>

<template>
    <div id="flame-container">
        <div class="header" style="font-size:18px;font-weight:500;line-height:34px;">
            <n-space justify="space-between">
                <div v-if="formData.objType === '0'">
                    账户：{{ formData.objId }} {{ title }}权限设置
                </div>
                <div v-if="formData.objType === '1'">
                    角色：{{ formData.objId }} {{ title }}权限设置
                </div>
                <div>
                    <n-button v-if="title === '功能'" quaternary @click="title = '数据'; listDataAuth();">数据权限设置</n-button>
                    <n-button v-if="title === '数据'" quaternary @click="title = '功能'">功能权限设置</n-button>
                    <n-button quaternary @click="router.back()">返回</n-button>
                </div>
            </n-space>
        </div>
        <div v-if="title === '功能'" class="data-table" style="top:72px;">
            <n-data-table :scrollbar-props="{ trigger: 'none' }" style="height:100%" flex-height :columns="columns"
                :data="menuTreeData" :row-key="(row: RowData) => row.value" :bordered="false"
                :checked-row-keys="selectedRowKeys" :on-update-checked-row-keys="onUpdateCheckedRowKeys" />
        </div>
        <div v-if="title === '数据'" class="data-table" style="top:72px;bottom:12px;">
            <data-auth-config v-model:user-data-auth="userDataAuth" :obj-id="formData.objId" :list-data-auth="listDataAuth"
                :org-data-auth-list="orgDataAuthList" :obj-type="formData.objType" />
        </div>
        <div v-if="title === '功能'" class="footer">
            <n-button style="float:right" v-if="title === '功能' && userStore.hasAuth('auth:edit')"
                @click="submit()">提交</n-button>
        </div>
    </div>
</template>

<style scoped></style>